%%%-------------------------------------------------------------------
%%% @author Rain
%%% @doc 行为模式 游戏服务器(基于gen_server)
%%% @end
%%%-------------------------------------------------------------------
-module(game_server).

-behaviour(gen_server).
-include("common.hrl").

-export([start_link/3, start_link/4]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
    code_change/3]).

-export_type([from/0, reply_tag/0]).

-type from() ::	{Client :: pid(), Tag :: reply_tag()}.
-opaque reply_tag() :: gen:reply_tag().

-callback init(Args :: term()) ->
    {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate | {continue, term()}} |
    {stop, Reason :: term()} | ignore.
-callback do_call(Request :: term(), From :: from(),
    State :: term()) ->
    {reply, Reply :: term(), NewState :: term()} |
    {reply, Reply :: term(), NewState :: term(), timeout() | hibernate | {continue, term()}} |
    {noreply, NewState :: term()} |
    {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} |
    {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
    {stop, Reason :: term(), NewState :: term()}.
-callback do_cast(Request :: term(), State :: term()) ->
    {noreply, NewState :: term()} |
    {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} |
    {stop, Reason :: term(), NewState :: term()}.
-callback do_info(Info :: timeout | term(), State :: term()) ->
    {noreply, NewState :: term()} |
    {noreply, NewState :: term(), timeout() | hibernate | {continue, term()}} |
    {stop, Reason :: term(), NewState :: term()}.
-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
term()),
    State :: term()) ->
    term().
-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(),
    Extra :: term()) ->
    {ok, NewState :: term()} | {error, Reason :: term()}.

%%%===================================================================
%%% Spawning and gen_server implementation
%%%===================================================================

start_link(Module, Args, Options) ->
    gen_server:start_link(?MODULE, [Module | Args], Options).
start_link(ServerName, Module, Args, Options) ->
    gen_server:start_link(ServerName, ?MODULE, [Module | Args], Options).

init([CbModule | Args]) ->
    set_cb_module(CbModule),
    CbModule:init(Args).

handle_call(Request, From, State) ->
    CbMod = cb_module(),
    try
        CbMod:do_call(Request, From, State)
    catch
        Class:Error:Stack ->
            ?LOG_ERROR("Mod: ~p do call error Class ~p Error ~p Stack ~p", [CbMod, Class, Error, Stack]),
            {noreply, State}
    end.

handle_cast(Request, State) ->
    CbMod = cb_module(),
    try
        CbMod:do_cast(Request, State)
    catch
        Class:Error:Stack ->
            ?LOG_ERROR("Mod: ~p do cast error Class ~p Error ~p Stack ~p", [CbMod, Class, Error, Stack]),
            {noreply, State}
    end.

handle_info(Info, State) ->
    CbMod = cb_module(),
    try
        CbMod:do_info(Info, State)
    catch
        Class:Error:Stack ->
            ?LOG_ERROR("Mod: ~p do info error Class ~p Error ~p Stack ~p", [CbMod, Class, Error, Stack]),
            {noreply, State}
    end.

terminate(Reason, State) ->
    CbMod = cb_module(),
    CbMod:terminate(Reason, State).

code_change(OldVsn, State, Extra) ->
    CbMod = cb_module(),
    CbMod:code_change(OldVsn, State, Extra).

cb_module() ->
    get(cb_module).

set_cb_module(Module) ->
    put(cb_module, Module).

%%%===================================================================
%%% Internal functions
%%%===================================================================
